<!--- Document Information -----------------------------------------------------

Title:      TransferInserter.cfc

Author:     Mark Mandel
Email:      mark@compoundtheory.com

Website:    http://www.compoundtheory.com

Purpose:    Inserts a transfer's details into the DB

Usage:

Modification Log:

Name			Date			Description
================================================================================
Mark Mandel		12/08/2005		Created

------------------------------------------------------------------------------->

<cfcomponent name="TransferInserter" hint="Inserts a transfer's details into the DB">

<cfscript>
	instance = StructNew();
</cfscript>

<!------------------------------------------- PUBLIC ------------------------------------------->
<cffunction name="init" hint="Constructor" access="public" returntype="TransferInserter" output="false">
	<cfargument name="Datasource" hint="The datasource BO" type="Datasource" required="Yes">
	<cfargument name="objectManager" hint="Need to object manager for making queries" type="transfer.com.object.ObjectManager" required="Yes">
	<cfargument name="utility" hint="The utility class" type="transfer.com.util.Utility" required="Yes">
	<cfargument name="nullable" hint="The nullable class" type="transfer.com.sql.Nullable" required="Yes">
	<cfargument name="transaction" hint="handles transactions" type="transfer.com.sql.Transaction" required="Yes">
	<cfscript>
		setDataSource(arguments.datasource);
		setObjectManager(arguments.objectManager);
		setNullable(arguments.nullable);
		setMethodInvoker(createObject("component", "transfer.com.dynamic.MethodInvoker").init());
		setIDGenerator(createObject("component", "IDGenerator").init(5, arguments.datasource, arguments.utility));
		setTransaction(arguments.transaction);

		return this;
	</cfscript>
</cffunction>

<cffunction name="create" hint="Inserts the transfer into the DB" access="public" returntype="void" output="false">
	<cfargument name="transfer" hint="The transfer object to insert" type="transfer.com.TransferObject" required="Yes">
	<cfargument name="useTransaction" hint="Whether or not to use an internal transaction block" type="boolean" required="true">

	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());
		var id = 0;

		/*
			create transaction, doing it this way to support postGres
		*/
	</cfscript>

	<cftry>
		<cfscript>
			getTransaction().begin(arguments.useTransaction);

			insertBasic(arguments.transfer);

			insertManyToMany(arguments.transfer);

			getTransaction().commit(arguments.useTransaction);
		</cfscript>

		<cfcatch type="any">
			<cfset getTransaction().rollback(arguments.useTransaction)>
			<cfrethrow>
		</cfcatch>
	</cftry>
</cffunction>

<!------------------------------------------- PACKAGE ------------------------------------------->

<!------------------------------------------- PRIVATE ------------------------------------------->

<cffunction name="setGeneratedPrimaryKey" hint="sets the TransferObject's primary key value with one generated by Transfer" access="private" returntype="void" output="false">
	<cfargument name="transfer" hint="The transfer object to insert" type="transfer.com.TransferObject" required="Yes">
	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());
		var id = 0;

		//get me an id please, numeric or UUID, or GUID
		switch(object.getPrimaryKey().getType())
		{
			case "numeric":
				id = getIDGenerator().getNumericID(object);
			break;

			case "uuid":
				id = getIDGenerator().getUUID();
			break;

			case "guid":
				id = getIDGenerator().getGUID();
			break;

			default:
				throw("UnsupportedAutoGenerateTypeExcpetion", "This type of ID cannot be generated by Transfer", "The type of '#object.getPrimaryKey().getType()#' is not of type 'numeric', 'UUID' or 'GUID'");
			break;
		}

		invokeSetPrimaryKey(arguments.transfer, id);
	</cfscript>
</cffunction>

<cffunction name="insertBasic" hint="Insert the single table part of the query. populates the transfer with it's primary key" access="private" returntype="void" output="false">
	<cfargument name="transfer" hint="The transfer object to insert" type="transfer.com.TransferObject" required="Yes">
	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());
		var qInsertTransfer = 0;
		var iterator = object.getPropertyIterator();
		var property = 0;
		var primaryKey = object.getPrimaryKey();
		var parentOneToMany = 0;
		var value = 0;
		var manytoone = 0;
		var hasComposite = 0;
		var composite = 0;
		var compositeObject = 0;
		var parent = 0;
		var hasParent = 0;
		var parentObject = 0;
		var isFirst = true;
		var primaryKeyHasValue = primaryKeyHasValue(arguments.transfer);
		var generateKey = object.getPrimaryKey().getGenerate() AND (NOT primaryKeyHasValue);
		var populateKey = (NOT object.getPrimaryKey().getGenerate()) AND (NOT primaryKeyHasValue);
		var sql = 0;
		var qBeforeInsertTransfer = 0;
		var qAfterInsertTransfer = 0;
		var isNull = false;

		/* generate the key if required */
		if(generateKey)
		{
			setGeneratedPrimaryKey(arguments.transfer);
		}
	</cfscript>

	<!--maybe you need to go before to populate the primary key --->
	<cfif populateKey>
		<cfset sql = sqlBeforeInsert(object)>
		<cfif len(sql)>
			<cfquery name="qBeforeInsertTransfer" datasource="#getDataSource().getName()#" username="#getDataSource().getUsername()#" password="#getDataSource().getPassword()#">
				#preserveSingleQuotes(sql)#
			</cfquery>
			<cfscript>
				invokeSetPrimaryKey(arguments.transfer, qBeforeInsertTransfer.id);
				primaryKeyHasValue = true;
			</cfscript>
		</cfif>
	</cfif>

	<cfquery name="qInsertTransfer" datasource="#getDataSource().getName()#" username="#getDataSource().getUsername()#" password="#getDataSource().getPassword()#">
	INSERT
	INTO
	#object.getTable()#
	(
		#createColumnList(object, primaryKeyHasValue)#
	)
	VALUES
	(
		<cfloop condition="#iterator.hasNext()#">
			<cfset property = iterator.next()>

			<!--- ignore any property that has ignore-insert='true' --->
			<cfif NOT property.getIgnoreInsert()>

				<cfif not isFirst>,</cfif>
				<cfset isFirst = false>

				<cfset value = getMethodInvoker().invokeMethod(transfer, "get" & property.getName())>
				<cfswitch expression="#property.getType()#">
					<cfcase value="numeric">
						<cfset isNull = property.getIsNullable() AND getNullable().checkNullNumeric(arguments.transfer, property.getName(), value)>
						<cfqueryparam value="#value#" cfsqltype="cf_sql_float" null="#isNull#">
					</cfcase>
					<cfcase value="date">
						<cfset isNull = property.getIsNullable() AND getNullable().checkNullDate(arguments.transfer, property.getName(), value)>
						<cfqueryparam value="#value#" cfsqltype="cf_sql_timestamp" null="#isNull#">
					</cfcase>
					<cfcase value="boolean">
						<cfset isNull = property.getIsNullable() AND getNullable().checkNullBoolean(arguments.transfer, property.getName(), value)>
						<cfqueryparam value="#value#" cfsqltype="cf_sql_bit" null="#isNull#">
					</cfcase>
					<cfcase value="uuid">
						<cfset isNull = property.getIsNullable() AND getNullable().checkNullUUID(arguments.transfer, property.getName(), value)>
						<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
					</cfcase>
					<cfcase value="guid">
						<cfset isNull = property.getIsNullable() AND getNullable().checkNullGUID(arguments.transfer, property.getName(), value)>
						<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
					</cfcase>
					<cfdefaultcase>
						<cfset isNull = property.getIsNullable() AND getNullable().checkNullString(arguments.transfer, property.getName(), value)>
						<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
					</cfdefaultcase>
				</cfswitch>

			</cfif>
		</cfloop>

		<!--- manytoone --->
		<cfscript>
			iterator = object.getManyToOneIterator();
		</cfscript>
		<cfloop condition="#iterator.hasNext()#">
			<cfif not isFirst>,</cfif>
			<cfset isFirst = false>
			<cfscript>
				manyToOne = iterator.next();

				hasComposite = getMethodInvoker().invokeMethod(arguments.transfer, "has" & manyToOne.getName());
				//get the defintion of the composite
				compositeObject = getObjectManager().getObject(manyToOne.getLink().getTo());

				//default values
				isNull = false;
				value = 0;

				if(hasComposite)
				{
					//get the composite
					composite = getMethodInvoker().invokeMethod(transfer, "get" & manyToOne.getName());

					//if not created, throw an excpetion
					if(not composite.getIsPersisted())
					{
						throw("ManyToOneNotCreatedException",
							  "The ManyToOne TransferObject has not been created.",
							  "In TransferObject '"& object.getClassName() &"' manytoone '"& compositeObject.getClassName() &"' has not been created in the database.");
					}

					//get it's primary key value
					value = invokeGetPrimaryKey(composite);
				}
				else
				{
					isNull = true;
				}
			</cfscript>
			<cfswitch expression="#compositeObject.getPrimaryKey().getType()#">
				<cfcase value="numeric">
					<cfset isNull = isNull OR getNullable().checkNullNumeric(composite, compositeObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_float" null="#isNull#">
				</cfcase>
				<cfcase value="date">
					<cfset isNull = isNull OR getNullable().checkNullDate(composite, compositeObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_timestamp" null="#isNull#">
				</cfcase>
				<cfcase value="boolean">
					<cfset isNull = isNull OR getNullable().checkNullBoolean(composite, compositeObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_bit" null="#isNull#">
				</cfcase>
				<cfcase value="uuid">
					<cfset isNull = isNull OR getNullable().checkNullUUID(composite, compositeObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
				</cfcase>
				<cfcase value="guid">
					<cfset isNull = isNull OR getNullable().checkNullGUID(composite, compositeObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
				</cfcase>
				<cfdefaultcase>
					<cfset isNull = isNull OR getNullable().checkNullString(composite, compositeObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
				</cfdefaultcase>
			</cfswitch>
		</cfloop>

		<!--- external one to many's' --->
		<cfset iterator = object.getParentOnetoManyIterator()>

		<cfloop condition="#iterator.hasNext()#">
			<cfscript>
				parentOneToMany = iterator.next();

				parentObject = getObjectManager().getObject(parentOneToMany.getLink().getTo());

				//check parent first
				hasParent = getMethodInvoker().invokeMethod(arguments.transfer, "hasParent" & parentObject.getObjectName());

				isNull = false;
				value = 0;

				if(hasParent)
				{
					//get the parent
					parent = getMethodInvoker().invokeMethod(arguments.transfer, "getParent" & parentObject.getObjectName());

					//make sure it's in the DB
					if(not parent.getIsPersisted())
					{
						throw("OneToManyNotCreatedException",
							  "The OneToMany TransferObject is not persisted.",
							  "In TransferObject '"& object.getClassName() &"' onetomany '"& parentObject.getClassName() &"' has not been created in the database.");
					}

					//method invoke the IDValue
					value = invokeGetPrimaryKey(parent);
				}
				else
				{
					isNull = true;
				}
			</cfscript>
			<cfif not isFirst>,</cfif>
			<cfset isFirst = false>

			<!--- set it --->
			<cfswitch expression="#parentObject.getPrimaryKey().getType()#">
				<cfcase value="numeric">
					<cfset isNull = isNull OR getNullable().checkNullNumeric(parent, parentObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_float" null="#isNull#">
				</cfcase>
				<cfcase value="date">
					<cfset isNull = isNull OR getNullable().checkNullDate(parent, parentObjectt.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_timestamp" null="#isNull#">
				</cfcase>
				<cfcase value="boolean">
					<cfset isNull = isNull OR getNullable().checkNullBoolean(parent, parentObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_bit" null="#isNull#">
				</cfcase>
				<cfcase value="uuid">
					<cfset isNull = isNull OR getNullable().checkNullUUID(parent, parentObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
				</cfcase>
				<cfcase value="guid">
					<cfset isNull = isNull OR getNullable().checkNullGUID(parent, parentObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
				</cfcase>
				<cfdefaultcase>
					<cfset isNull = isNull OR getNullable().checkNullString(parent, parentObject.getPrimaryKey().getName(), value)>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar" null="#isNull#">
				</cfdefaultcase>
			</cfswitch>
		</cfloop>


		<!--- only do this if generating key --->
		<cfif generateKey OR primaryKeyHasValue>
			<cfif not isFirst>,</cfif>

			<!--- primary key --->
			<cfset value = invokeGetPrimaryKey(transfer)>

			<cfswitch expression="#primaryKey.getType()#">
				<cfcase value="numeric">
					<cfqueryparam value="#value#" cfsqltype="cf_sql_float">
				</cfcase>
				<cfcase value="date">
					<cfqueryparam value="#value#" cfsqltype="cf_sql_timestamp">
				</cfcase>
				<cfcase value="boolean">
					<cfqueryparam value="#value#" cfsqltype="cf_sql_bit">
				</cfcase>
				<cfdefaultcase>
					<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar">
				</cfdefaultcase>
			</cfswitch>

		</cfif>
	)

		<!--- if populate, --->
		<cfif populateKey>
			<cfset sql = sqlInsideInsert(object)>
			<cfif len(sql)>
				;
				#preserveSingleQuotes(sql)#
			</cfif>
		</cfif>
	</cfquery>

	<!--maybe you need to go outside to populate the primary key --->
	<cfif populateKey>
		<cfset sql = sqlAfterInsert(object)>
		<cfif len(sql)>
			<cfquery name="qAfterInsertTransfer" datasource="#getDataSource().getName()#" username="#getDataSource().getUsername()#" password="#getDataSource().getPassword()#">
				#preserveSingleQuotes(sql)#
			</cfquery>
		</cfif>
	</cfif>

	<cfscript>
		//if not auto generating -
		if(NOT primaryKeyHasValue AND populateKey)
		{
			//check then qInside, then qAfter, if none, throw an exception
			if(IsDefined("qInsertTransfer") AND IsQuery(qInsertTransfer) AND ListFindNoCase(qInsertTransfer.columnList, "id"))
			{
				invokeSetPrimaryKey(arguments.transfer, qInsertTransfer.id);
			}
			else
			{
				invokeSetPrimaryKey(arguments.transfer, qAfterInsertTransfer.id);
			}
		}
	</cfscript>
</cffunction>

<cffunction name="insertManyToMany" hint="Updates the many to many portion of the transfer" access="private" returntype="void" output="false">
	<cfargument name="transfer" hint="The transferObject to update" type="transfer.com.TransferObject" required="Yes">
	<cfscript>
		var qInsertTransfer = 0;
		var object = getObjectManager().getObject(arguments.transfer.getClassName());
		var primaryKey = object.getPrimaryKey();
		var primaryKeyValue = invokeGetPrimaryKey(transfer);
		var composite = 0;
		var compositeObject = 0;
		var iterator = object.getManyToManyIterator();
		var manytomany = 0;
		var value = 0;
	</cfscript>

	<cfloop condition="#iterator.hasNext()#">
		<cfset manytomany = iterator.next()>
		<cfset collectionIterator = getMethodInvoker().invokeMethod(transfer, "get" & manyToMany.getName() & "Iterator")>

		<!--- now go through and reinsert the values --->
		<cfloop condition="#collectionIterator.hasNext()#">
			<cfscript>
				composite = collectionIterator.next();
				compositeObject = getObjectManager().getObject(manyToMany.getLinkTo().getTo());

				if(NOT composite.getIsPersisted())
				{
					throw("ManyToManyNotCreatedException",
							  "A ManyToMany TransferObject child is not persisted.",
							  "In TransferObject '"& object.getClassName() &"' manytomany '"& composite.getClassName() &"' has either not been created in the database.");
				}

				value = invokeGetPrimaryKey(composite);
			</cfscript>
			<cfquery name="qInsertTransfer" datasource="#getDataSource().getName()#" username="#getDataSource().getUsername()#" password="#getDataSource().getPassword()#">
				INSERT INTO
					#manytomany.getTable()#
				(
					#manyToMany.getLinkFrom().getColumn()#,
					#manyToMany.getLinkTo().getColumn()#
				)
				VALUES
				(
					<cfswitch expression="#primaryKey.getType()#">
						<cfcase value="numeric">
							<cfqueryparam value="#primaryKeyValue#" cfsqltype="cf_sql_float">
						</cfcase>
						<cfcase value="date">
							<cfqueryparam value="#primaryKeyValue#" cfsqltype="cf_sql_timestamp">
						</cfcase>
						<cfcase value="boolean">
							<cfqueryparam value="#primaryKeyValue#" cfsqltype="cf_sql_bit">
						</cfcase>
						<cfdefaultcase>
							<cfqueryparam value="#primaryKeyValue#" cfsqltype="cf_sql_varchar">
						</cfdefaultcase>
					</cfswitch>,
					<cfswitch expression="#compositeObject.getPrimaryKey().getType()#">
						<cfcase value="numeric">
							<cfqueryparam value="#value#" cfsqltype="cf_sql_float">
						</cfcase>
						<cfcase value="date">
							<cfqueryparam value="#value#" cfsqltype="cf_sql_timestamp">
						</cfcase>
						<cfcase value="boolean">
							<cfqueryparam value="#value#" cfsqltype="cf_sql_bit">
						</cfcase>
						<cfdefaultcase>
							<cfqueryparam value="#value#" cfsqltype="cf_sql_varchar">
						</cfdefaultcase>
					</cfswitch>
				)
			</cfquery>
		</cfloop>

	</cfloop>
</cffunction>

<cffunction name="sqlBeforeInsert" hint="Overwrite to run SQL directly before the insert query (no generation). Should select a 'id' column for id population" access="private" returntype="string" output="false">
	<cfargument name="object" hint="The oject that is being inserted" type="transfer.com.object.Object" required="Yes">
	<cfreturn "">
</cffunction>


<cffunction name="sqlInsideInsert" hint="Overwrite method to run SQL inside the insert query (with no generation), and before the end of the cfquery block. Should select a 'id' column for id population" access="private" returntype="string" output="false">
	<cfargument name="object" hint="The oject that is being inserted" type="transfer.com.object.Object" required="Yes">
	<cfreturn "">
</cffunction>

<cffunction name="sqlAfterInsert" hint="Overwrite to run SQL directly after the insert query (no generation). Should select a 'id' column for id population" access="private" returntype="string" output="false">
	<cfargument name="object" hint="The oject that is being inserted" type="transfer.com.object.Object" required="Yes">
	<cfreturn "">
</cffunction>

<cffunction name="createColumnList" hint="Creates the column list to insert" access="private" returntype="string" output="false">
	<cfargument name="object" hint="The oject that is being inserted" type="transfer.com.object.Object" required="Yes">
	<cfargument name="primaryKeyHasValue" hint="Pass through if the primary key has value already" type="boolean" required="Yes">
	<cfscript>
		var columnList = "";
		var property = 0;
		var manytoone = 0;
		//var qOneToMany = getObjectManager().getClassName ByOneToManyLinkTo(arguments.object.getClassName());
		var parentOneToMany = 0;
		var iterator = arguments.object.getPropertyIterator();

		//properties
		while(iterator.hasNext())
		{
			property = iterator.next();

			//remove ignore inserts
			if(NOT property.getIgnoreInsert())
			{
				columnList = ListAppend(columnList, property.getColumn());
			}
		}

		//many to one
		iterator = arguments.object.getManyToOneIterator();
		while(iterator.hasNext())
		{
			manytoone = iterator.next();
			columnList = ListAppend(columnList, manyToOne.getLink().getColumn());
		}

		iterator = arguments.object.getParentOneToManyIterator();
		while(iterator.hasNext())
		{
			parentOneToMany = iterator.next();
			columnList = ListAppend(columnList, parentOneToMany.getLink().getColumn());
		}

		//if we add a primary key, add it
		if(primaryKeyHasValue OR arguments.object.getPrimaryKey().getGenerate())
		{
			columnList = ListAppend(columnList, arguments.object.getPrimaryKey().getColumn());
		}

		return columnList;
	</cfscript>
</cffunction>

<cffunction name="invokeSetPrimaryKey" hint="Invokes the setPrimaryKey method on the transfer object" access="private" returntype="void" output="false">
	<cfargument name="transfer" hint="The transfer object to insert" type="transfer.com.TransferObject" required="Yes">
	<cfargument name="primarykeyvalue" hint="The primary key value" type="string" required="Yes">
	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());
		var args = StructNew();

		args[object.getPrimaryKey().getName()] = arguments.primarykeyvalue;

		getMethodInvoker().invokeMethod(arguments.transfer,
										"set" & object.getPrimaryKey().getName(),
										args);
	</cfscript>
</cffunction>

<!--- <cffunction name="getNullValueByPrimaryKey" access="private" returntype="string" output="false">
	<cfargument name="transfer" type="transfer.com.TransferObject" required="true" hint="The transferObject to get the null primary key value for">
	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());
		var primaryKey = arguments.object.getPrimaryKey();

		switch(primaryKey.getType())
		{
			case "numeric":
				return getNullable().getNullNumeric(arguments.transfer, primaryKey.getName());
			break;
			case "uuid":
				return getNullable().getNullUUID(arguments.transfer, primaryKey.getName());
			break;
			case "guid":
				return getNullable().getNullGUID(arguments.transfer, primaryKey.getName());
			break;
			case "date":
				return getNullable().getNullDate(arguments.transfer, primaryKey.getName());
			break;
			case "boolean":
				return getNullable().getNullBoolean(arguments.transfer, primaryKey.getName());
			break;
			default:
				return getNullable().getNullString(arguments.transfer, primaryKey.getName());
		}
	</cfscript>
</cffunction> --->

<!--- <cffunction name="checkNullValueByPrimaryKey" access="private" returntype="boolean" output="false">
	<cfargument name="transfer" type="transfer.com.TransferObject" required="true" hint="The transferObject to get the null primary key value for">
	<cfargument name="value" hint="The value to check" type="any" required="Yes">
	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());
		var primaryKey = object.getPrimaryKey();

		switch(primaryKey.getType())
		{
			case "numeric":
				return getNullable().checkNullNumeric(arguments.transfer, primaryKey.getName(), arguments.value);
			break;
			case "uuid":
				return getNullable().checkNullUUID(arguments.transfer, primaryKey.getName(), arguments.value);
			break;
			case "guid":
				return getNullable().checkNullGUID(arguments.transfer, primaryKey.getName(), arguments.value);
			break;
			case "date":
				return getNullable().checkNullDate(arguments.transfer, primaryKey.getName(), arguments.value);
			break;
			case "boolean":
				return getNullable().checkNullBoolean(arguments.transfer, primaryKey.getName(), arguments.value);
			break;
			default:
				return getNullable().checkNullString(arguments.transfer, primaryKey.getName(), arguments.value);
		}
	</cfscript>
</cffunction> --->

<cffunction name="invokeGetPrimaryKey" hint="Gets the primary key value from an object" access="private" returntype="any" output="false">
	<cfargument name="transfer" hint="The transfer object to insert" type="transfer.com.TransferObject" required="Yes">
	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());

		return getMethodInvoker().invokeMethod(arguments.transfer, "get" & object.getPrimaryKey().getName());
	</cfscript>
</cffunction>

<cffunction name="primaryKeyHasValue" hint="Checks to see if the object's primary key has a value other than default" access="private" returntype="boolean" output="false">
	<cfargument name="transfer" hint="The transfer object" type="transfer.com.TransferObject" required="Yes">
	<cfscript>
		var object = getObjectManager().getObject(arguments.transfer.getClassName());

		//return NOT checkNullValueByPrimaryKey(arguments.transfer, invokeGetPrimaryKey(arguments.transfer));
		return NOT getNullable().checkNullValue(arguments.transfer, object.getPrimaryKey().getName(), invokeGetPrimaryKey(arguments.transfer));
	</cfscript>
</cffunction>

<cffunction name="getDatasource" access="private" returntype="Datasource" output="false">
	<cfreturn instance.Datasource />
</cffunction>

<cffunction name="setDatasource" access="private" returntype="void" output="false">
	<cfargument name="Datasource" type="Datasource" required="true">
	<cfset instance.Datasource = arguments.Datasource />
</cffunction>

<cffunction name="getObjectManager" access="private" returntype="transfer.com.object.ObjectManager" output="false">
	<cfreturn instance.ObjectManager />
</cffunction>

<cffunction name="setObjectManager" access="private" returntype="void" output="false">
	<cfargument name="ObjectManager" type="transfer.com.object.ObjectManager" required="true">
	<cfset instance.ObjectManager = arguments.ObjectManager />
</cffunction>

<cffunction name="getMethodInvoker" access="private" returntype="transfer.com.dynamic.MethodInvoker" output="false">
	<cfreturn instance.MethodInvoker />
</cffunction>

<cffunction name="setMethodInvoker" access="private" returntype="void" output="false">
	<cfargument name="MethodInvoker" type="transfer.com.dynamic.MethodInvoker" required="true">
	<cfset instance.MethodInvoker = arguments.MethodInvoker />
</cffunction>

<cffunction name="getIDGenerator" access="private" returntype="IDGenerator" output="false">
	<cfreturn instance.IDGenerator />
</cffunction>

<cffunction name="setIDGenerator" access="private" returntype="void" output="false">
	<cfargument name="IDGenerator" type="IDGenerator" required="true">
	<cfset instance.IDGenerator = arguments.IDGenerator />
</cffunction>

<cffunction name="getNullable" access="private" returntype="Nullable" output="false">
	<cfreturn instance.Nullable />
</cffunction>

<cffunction name="setNullable" access="private" returntype="void" output="false">
	<cfargument name="Nullable" type="Nullable" required="true">
	<cfset instance.Nullable = arguments.Nullable />
</cffunction>

<cffunction name="getTransaction" access="private" returntype="transfer.com.sql.Transaction" output="false">
	<cfreturn instance.Transaction />
</cffunction>

<cffunction name="setTransaction" access="private" returntype="void" output="false">
	<cfargument name="Transaction" type="transfer.com.sql.Transaction" required="true">
	<cfset instance.Transaction = arguments.Transaction />
</cffunction>

<cffunction name="throw" access="private" hint="Throws an Exception" output="false">
	<cfargument name="type" hint="The type of exception" type="string" required="Yes">
	<cfargument name="message" hint="The message to accompany the exception" type="string" required="Yes">
	<cfargument name="detail" type="string" hint="The detail message for the exception" required="No" default="">
		<cfthrow type="#arguments.type#" message="#arguments.message#" detail="#arguments.detail#">
</cffunction>

</cfcomponent>